﻿
namespace BackupLib
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Threading;
    using System.Xml.Serialization;

    /// <summary>
    /// cumulation of multiple backup tasks
    /// </summary>
    public class BackupProject: INotifyPropertyChanged, IBackupTask
    {
        public DateTime ExecutionTime { get; set; }
        public bool OnlyArchiveAttribute { get; set; }
        public bool ResetArchiveAttribute { get; set; }
        public int Retry { get; set; }
        public int TimeBetweenRetry { get; set; }

        private TimeSpan _scheduleTime;
        [XmlIgnore]
        public TimeSpan ScheduleTime
        {
            get { return _scheduleTime; }
            set { _scheduleTime = value; NotifyPropertyChanged("ScheduleTime"); }
        }
        [XmlElement("ScheduleTime")]
        public string XmlScheduleTime
        {
            get { return _scheduleTime.ToString(); }
            set { _scheduleTime = TimeSpan.Parse(value); }
        }

        private DayOfWeek _scheduleDay;
        [XmlIgnore]
        public DayOfWeek ScheduleDay
        {
            get { return _scheduleDay; }
            set { _scheduleDay = value; NotifyPropertyChanged("ScheduleDay"); }
        }
        [XmlElement("ScheduleDay")]
        public string XmlScheduleDay
        {
            get { return _scheduleDay.ToString(); }
            set { _scheduleDay =(DayOfWeek)Enum.Parse(typeof(DayOfWeek),value); }
        }

        private ObservableCollection<BackupTask> _tasks;
        public ObservableCollection<BackupTask> Tasks
        {
            get { return _tasks; }
            set { _tasks = value; NotifyPropertyChanged("Tasks"); }
        }

        public event EventHandler<BackupFileEventArgs> OnFile;
        public event EventHandler<BackupEventArgs> OnStart;
        public event EventHandler<BackupFinishedEventArgs> OnStop;

        private Thread BackupThread;


        public BackupProject()
        {
            Tasks = new ObservableCollection<BackupTask>();
        }

        public ObservableCollection<string> DoBackup()
        {
            BackupThread = Thread.CurrentThread;
            List<string> failed =new List<string>();
            DateTime jetzt = DateTime.Now;
            foreach (BackupTask task in Tasks)
            {
                task.OnFile += new EventHandler<BackupFileEventArgs>(task_OnFile);
                task.OnStart += new EventHandler<BackupEventArgs>(task_OnStart);
                task.OnStop += new EventHandler<BackupFinishedEventArgs>(task_OnStop);
                task.ExecutionStart = jetzt;
                failed.AddRange(task.DoBackup());
            }

            if (failed.Count > 0)
            {
                for (int i = 0; i < Retry; i++)
                {
                    failed = new List<string>();
                    System.Threading.Thread.Sleep(TimeBetweenRetry);
                    foreach (BackupTask task in Tasks)
                    {
                        if (task.Failed.Count != 0)
                        {
                            BackupTask failedTask = new BackupTask();
                            foreach (string failedFile in task.Failed)
                            {
                                failedTask.Includes.Add(failedFile);
                            }
                            failedTask.ExecutionStart = jetzt;
                            task.Failed = failedTask.DoBackup();
                            failed.AddRange(task.Failed);
                        }
                    }
                }
            }

            return new ObservableCollection<string>(failed);
        }

        public bool IsProcessing
        {
            get; set;
        }

        public void ReloadProject()
        {
        }

        public void Pause()
        {
            if (BackupThread.IsAlive)
            {
                BackupThread.Interrupt();
            }
            else
            {
                BackupThread.Start();
            }
        }

        public void Stop()
        {
            BackupThread.Abort();
        }

        void task_OnStop(object sender, BackupFinishedEventArgs e)
        {
            if (OnStop != null)
                OnStop(this, e);
        }

        void task_OnStart(object sender, BackupEventArgs e)
        {
            if (OnStart != null)
                OnStart(this, e);
        }

        public DateTime GetNextExecution()
        {
            int daydiff = ScheduleDay - DateTime.Now.DayOfWeek;
            if (daydiff < 1) {
                daydiff += 7; }
            var retval=DateTime.Now.AddDays(daydiff);
            retval = retval.Add(ScheduleTime-retval.TimeOfDay);
            return retval;
        }

        void task_OnFile(object sender, BackupFileEventArgs e)
        {
            if (OnFile != null)
                OnFile(this, e);
        }

        public bool MatchesPath(string filename) 
        {
            foreach (BackupTask task in Tasks)
            {
                if (filename.StartsWith(task.SourceRoot))
                {
                    return true;
                }
            }
            return false;
        }

        public bool MatchesCriteria(string filename)
        {
            foreach (BackupTask task in Tasks)
            {
                if (!task.MatchesCriteria(filename))
                {
                    return false;
                }
            }
            return true;
        }

        public void AddTask(BackupTask task)
        {
            Tasks.Add(task);
        }

        #region INotifyPropertyChanged Member

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }        

        #endregion
    }
}
